package com.gjy.design.strategy.compression;

import org.xerial.snappy.SnappyInputStream;
import org.xerial.snappy.SnappyOutputStream;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;

/**
 * Snappy压缩策略的具体实现。
 * Snappy是一个注重压缩/解压速度而非压缩比的库。
 * 它同样是流式压缩，不原生支持归档。
 * 此实现约定与GZIP相同：compress()只处理第一个源文件，不支持文件夹。
 * 为了区分，压缩后的文件默认添加.snappy扩展名。
 *
 * @author gjy
 * @version 1.0
 * @since 2025-11-06 14:47:40
 */
public class SnappyCompressionStrategy implements CompressionStrategy {

    @Override
    public void compress(File[] source, File target) throws IOException {
        if (source == null || source.length == 0) {
            throw new IllegalArgumentException("源文件/文件夹数组不能为空");
        }
        if (source.length > 1) {
            System.err.println("警告: Snappy格式不支持压缩多个文件到单个归档。将只处理第一个源文件: " + source[0].getAbsolutePath());
        }

        File fileToCompress = source[0];
        if (fileToCompress.isDirectory()) {
            throw new UnsupportedOperationException("Snappy不支持压缩文件夹。");
        }

        // SnappyOutputStream不带文件头信息，通常需要自己处理或约定文件扩展名
        try (OutputStream fos = Files.newOutputStream(target.toPath());
             SnappyOutputStream sos = new SnappyOutputStream(fos);
             InputStream fis = Files.newInputStream(fileToCompress.toPath())) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = fis.read(buffer)) > 0) {
                sos.write(buffer, 0, len);
            }
        }
    }

    @Override
    public void decompress(File source, File target) throws IOException {
        if (!source.isFile()) {
            throw new IllegalArgumentException("源文件必须是文件，而不是目录");
        }
        if (target.exists() && target.isDirectory()) {
            // 如果目标是目录，将解压后的文件放在该目录下
            File decompressedFile = new File(target, getDecompressedFileName(source.getName()));
            decompressToFile(source, decompressedFile);
        } else if (target.exists() || !target.isDirectory()) {
            // 如果目标是文件或不存在的文件路径，直接解压到该文件
            decompressToFile(source, target);
        } else {
            throw new IOException("目标路径无效，已存在同名目录: " + target.getAbsolutePath());
        }
    }

    private void decompressToFile(File source, File target) throws IOException {
        File parent = target.getParentFile();
        if (parent != null && !parent.exists()) {
            parent.mkdirs();
        }

        try (InputStream fis = Files.newInputStream(source.toPath());
             SnappyInputStream sis = new SnappyInputStream(fis);
             OutputStream fos = Files.newOutputStream(target.toPath())) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = sis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
        }
    }

    private String getDecompressedFileName(String snappyFileName) {
        if (snappyFileName.toLowerCase().endsWith(".snappy")) {
            return snappyFileName.substring(0, snappyFileName.length() - ".snappy".length());
        }
        return snappyFileName + ".decompressed";
    }

}
